/**
 * 缓存辅助类
 */

const util = require('../helpers/util.js');

// 缓存时间，以秒为单位
const CACHE_TIME = {
    SHORT: 60, // 1分钟
    NORMAL: 600, // 10分钟
    LONG: 1800, // 30分钟
    DAY: 86400, // 1天
    WEEK: 604800, // 1周
};

// 缓存分组
const CACHE_GROUP = {
    SYSTEM: 'system',    // 系统缓存
    USER: 'user',        // 用户相关缓存
    LIST: 'list',        // 列表数据缓存
    DETAIL: 'detail',    // 详情数据缓存
    CONFIG: 'config',    // 配置缓存
    TEMP: 'temp'         // 临时缓存
};

// 缓存优先级
const CACHE_PRIORITY = {
    HIGH: 3,    // 高优先级，最后清理
    NORMAL: 2,  // 普通优先级
    LOW: 1      // 低优先级，最先清理
};

// 缓存容量限制(KB)
const CACHE_LIMIT = {
    TOTAL: 10240,  // 总缓存限制10MB
    GROUP: {       // 分组缓存限制
        [CACHE_GROUP.SYSTEM]: 1024,  // 系统缓存限制1MB
        [CACHE_GROUP.USER]: 2048,    // 用户缓存限制2MB
        [CACHE_GROUP.LIST]: 4096,    // 列表缓存限制4MB
        [CACHE_GROUP.DETAIL]: 2048,  // 详情缓存限制2MB
        [CACHE_GROUP.CONFIG]: 512,   // 配置缓存限制512KB
        [CACHE_GROUP.TEMP]: 512      // 临时缓存限制512KB
    }
};

// 监控器间隔(毫秒)
const MONITOR_INTERVAL = 60000; // 1分钟
let monitorTimer = null;

/**
 * 设置缓存
 * @param {string} key 缓存键
 * @param {any} value 缓存值
 * @param {number} expires 过期时间（秒）
 * @param {string} group 缓存分组
 * @param {number} priority 缓存优先级
 */
function set(key, value, expires = CACHE_TIME.NORMAL, group = CACHE_GROUP.TEMP, priority = CACHE_PRIORITY.NORMAL) {
    if (!key) return false;
    
    // 设置过期时间
    const expireTime = util.time() + expires;
    
    // 估算数据大小
    const dataSize = estimateSize(value);
    
    // 组装缓存数据
    const cacheData = {
        data: value,
        expireTime,
        group,
        priority,
        size: dataSize,
        createTime: util.time(),
        lastAccess: util.time()
    };
    
    try {
        // 检查缓存容量，如果空间不足，执行清理
        checkAndCleanCache(group, dataSize);
        
        // 设置缓存
        wx.setStorageSync(key, cacheData);
        
        // 添加到缓存索引
        addToCacheIndex(key, group, priority, dataSize);
        
        // 启动监控器（如果尚未启动）
        startMonitor();
        
        return true;
    } catch (e) {
        console.error('缓存设置失败:', e);
        return false;
    }
}

/**
 * 获取缓存
 * @param {string} key 缓存键
 * @param {any} defaultValue 默认值
 */
function get(key, defaultValue = null) {
    if (!key) return defaultValue;
    
    try {
        const cacheData = wx.getStorageSync(key);
        
        // 如果没有缓存数据
        if (!cacheData || !cacheData.data) {
            return defaultValue;
        }
        
        // 如果已过期
        if (cacheData.expireTime < util.time()) {
            wx.removeStorageSync(key);
            removeFromCacheIndex(key);
            return defaultValue;
        }
        
        // 更新最后访问时间
        cacheData.lastAccess = util.time();
        wx.setStorageSync(key, cacheData);
        updateCacheIndexAccess(key);
        
        return cacheData.data;
    } catch (e) {
        console.error('缓存获取失败:', e);
        return defaultValue;
    }
}

/**
 * 删除缓存
 * @param {string} key 缓存键
 */
function remove(key) {
    if (!key) return false;
    
    try {
        wx.removeStorageSync(key);
        removeFromCacheIndex(key);
        return true;
    } catch (e) {
        console.error('缓存删除失败:', e);
        return false;
    }
}

/**
 * 清空所有缓存
 */
function clear() {
    try {
        wx.clearStorageSync();
        clearCacheIndex();
        return true;
    } catch (e) {
        console.error('缓存清空失败:', e);
        return false;
    }
}

/**
 * 检查缓存是否存在
 * @param {string} key 缓存键
 */
function has(key) {
    if (!key) return false;
    
    try {
        const cacheData = wx.getStorageSync(key);
        
        // 如果没有缓存数据
        if (!cacheData || !cacheData.data) {
            return false;
        }
        
        // 如果已过期
        if (cacheData.expireTime < util.time()) {
            wx.removeStorageSync(key);
            removeFromCacheIndex(key);
            return false;
        }
        
        return true;
    } catch (e) {
        console.error('缓存检查失败:', e);
        return false;
    }
}

/**
 * 按分组清理缓存
 * @param {string} group 缓存分组
 */
function clearGroup(group) {
    if (!group) return false;
    
    try {
        const cacheIndex = getCacheIndex();
        const groupKeys = cacheIndex.groups[group] || [];
        
        // 删除该分组的所有缓存
        groupKeys.forEach(key => {
            wx.removeStorageSync(key);
        });
        
        // 更新缓存索引
        if (cacheIndex.groups[group]) {
            delete cacheIndex.groups[group];
        }
        
        // 从键列表中删除
        cacheIndex.keys = cacheIndex.keys.filter(item => !groupKeys.includes(item.key));
        
        // 保存更新后的索引
        saveCacheIndex(cacheIndex);
        
        return true;
    } catch (e) {
        console.error('分组缓存清理失败:', e);
        return false;
    }
}

/**
 * 获取缓存使用情况统计
 */
function getStats() {
    try {
        const cacheIndex = getCacheIndex();
        const stats = {
            total: {
                count: 0,
                size: 0
            },
            groups: {}
        };
        
        // 初始化分组统计
        Object.keys(CACHE_GROUP).forEach(key => {
            const group = CACHE_GROUP[key];
            stats.groups[group] = {
                count: 0,
                size: 0,
                limit: CACHE_LIMIT.GROUP[group] || 0
            };
        });
        
        // 统计各分组数据
        cacheIndex.keys.forEach(item => {
            stats.total.count++;
            stats.total.size += item.size;
            
            if (stats.groups[item.group]) {
                stats.groups[item.group].count++;
                stats.groups[item.group].size += item.size;
            }
        });
        
        // 添加总限制
        stats.total.limit = CACHE_LIMIT.TOTAL;
        
        return stats;
    } catch (e) {
        console.error('获取缓存统计失败:', e);
        return null;
    }
}

/**
 * 检查并清理缓存
 * @param {string} group 当前缓存分组
 * @param {number} size 当前缓存大小
 */
function checkAndCleanCache(group, size) {
    try {
        const stats = getStats();
        if (!stats) return;
        
        // 检查分组限制
        if (stats.groups[group] && stats.groups[group].size + size > stats.groups[group].limit) {
            // 清理当前分组的低优先级缓存
            cleanCacheByPriority(group);
        }
        
        // 检查总限制
        if (stats.total.size + size > stats.total.limit) {
            // 从所有分组清理低优先级缓存
            Object.keys(CACHE_GROUP).forEach(key => {
                const groupName = CACHE_GROUP[key];
                cleanCacheByPriority(groupName);
            });
        }
    } catch (e) {
        console.error('缓存清理检查失败:', e);
    }
}

/**
 * 根据优先级清理缓存
 * @param {string} group 缓存分组
 */
function cleanCacheByPriority(group) {
    try {
        const cacheIndex = getCacheIndex();
        const groupKeys = cacheIndex.groups[group] || [];
        
        if (groupKeys.length === 0) return;
        
        // 获取该分组的所有缓存项
        const groupItems = cacheIndex.keys.filter(item => item.group === group);
        
        // 按优先级和最后访问时间排序（低优先级、最久未访问的排在前面）
        groupItems.sort((a, b) => {
            if (a.priority !== b.priority) {
                return a.priority - b.priority;
            }
            return a.lastAccess - b.lastAccess;
        });
        
        // 清理排在前面的30%的缓存项
        const cleanCount = Math.max(1, Math.floor(groupItems.length * 0.3));
        const itemsToClean = groupItems.slice(0, cleanCount);
        
        // 执行清理
        itemsToClean.forEach(item => {
            wx.removeStorageSync(item.key);
            removeFromCacheIndex(item.key);
        });
        
    } catch (e) {
        console.error('按优先级清理缓存失败:', e);
    }
}

/**
 * 估算数据大小（KB）
 * @param {any} data 数据
 */
function estimateSize(data) {
    try {
        if (data === null || data === undefined) {
            return 0;
        }
        
        if (typeof data === 'string') {
            return data.length * 2 / 1024; // 估计字符串每个字符占2字节
        }
        
        if (typeof data === 'number') {
            return 8 / 1024; // 数字类型按8字节计算
        }
        
        if (typeof data === 'boolean') {
            return 4 / 1024; // 布尔类型按4字节计算
        }
        
        if (Array.isArray(data)) {
            return data.reduce((size, item) => size + estimateSize(item), 0);
        }
        
        if (typeof data === 'object') {
            let size = 0;
            for (const key in data) {
                if (data.hasOwnProperty(key)) {
                    // 键名占用加值占用
                    size += (key.length * 2 / 1024) + estimateSize(data[key]);
                }
            }
            return size;
        }
        
        // 默认按1KB处理
        return 1;
    } catch (e) {
        console.error('估算数据大小失败:', e);
        return 1; // 默认1KB
    }
}

/**
 * 获取缓存索引
 */
function getCacheIndex() {
    try {
        const cacheIndex = wx.getStorageSync('__CACHE_INDEX__');
        if (cacheIndex) {
            return cacheIndex;
        }
        
        // 如果不存在，创建一个新的索引
        const newIndex = {
            keys: [], // [{key, group, priority, size, createTime, lastAccess}]
            groups: {} // {group: [key1, key2, ...]}
        };
        
        // 初始化分组
        Object.keys(CACHE_GROUP).forEach(key => {
            newIndex.groups[CACHE_GROUP[key]] = [];
        });
        
        // 保存新索引
        wx.setStorageSync('__CACHE_INDEX__', newIndex);
        
        return newIndex;
    } catch (e) {
        console.error('获取缓存索引失败:', e);
        return {
            keys: [],
            groups: {}
        };
    }
}

/**
 * 保存缓存索引
 * @param {object} cacheIndex 缓存索引
 */
function saveCacheIndex(cacheIndex) {
    try {
        wx.setStorageSync('__CACHE_INDEX__', cacheIndex);
    } catch (e) {
        console.error('保存缓存索引失败:', e);
    }
}

/**
 * 添加到缓存索引
 * @param {string} key 缓存键
 * @param {string} group 缓存分组
 * @param {number} priority 缓存优先级
 * @param {number} size 缓存大小
 */
function addToCacheIndex(key, group, priority, size) {
    try {
        const cacheIndex = getCacheIndex();
        
        // 检查键是否已存在
        const existingIndex = cacheIndex.keys.findIndex(item => item.key === key);
        if (existingIndex >= 0) {
            // 更新现有项
            cacheIndex.keys[existingIndex] = {
                key,
                group,
                priority,
                size,
                createTime: util.time(),
                lastAccess: util.time()
            };
        } else {
            // 添加新项
            cacheIndex.keys.push({
                key,
                group,
                priority,
                size,
                createTime: util.time(),
                lastAccess: util.time()
            });
            
            // 添加到分组
            if (!cacheIndex.groups[group]) {
                cacheIndex.groups[group] = [];
            }
            
            if (!cacheIndex.groups[group].includes(key)) {
                cacheIndex.groups[group].push(key);
            }
        }
        
        // 保存更新后的索引
        saveCacheIndex(cacheIndex);
    } catch (e) {
        console.error('添加缓存索引失败:', e);
    }
}

/**
 * 从缓存索引中移除
 * @param {string} key 缓存键
 */
function removeFromCacheIndex(key) {
    try {
        const cacheIndex = getCacheIndex();
        
        // 查找键索引
        const keyItem = cacheIndex.keys.find(item => item.key === key);
        if (keyItem) {
            const group = keyItem.group;
            
            // 从键列表中移除
            cacheIndex.keys = cacheIndex.keys.filter(item => item.key !== key);
            
            // 从分组中移除
            if (cacheIndex.groups[group]) {
                cacheIndex.groups[group] = cacheIndex.groups[group].filter(k => k !== key);
            }
            
            // 保存更新后的索引
            saveCacheIndex(cacheIndex);
        }
    } catch (e) {
        console.error('从缓存索引移除失败:', e);
    }
}

/**
 * 更新缓存索引访问时间
 * @param {string} key 缓存键
 */
function updateCacheIndexAccess(key) {
    try {
        const cacheIndex = getCacheIndex();
        
        // 更新键的最后访问时间
        const keyIndex = cacheIndex.keys.findIndex(item => item.key === key);
        if (keyIndex >= 0) {
            cacheIndex.keys[keyIndex].lastAccess = util.time();
            
            // 保存更新后的索引
            saveCacheIndex(cacheIndex);
        }
    } catch (e) {
        console.error('更新缓存索引访问时间失败:', e);
    }
}

/**
 * 清空缓存索引
 */
function clearCacheIndex() {
    try {
        const newIndex = {
            keys: [],
            groups: {}
        };
        
        // 初始化分组
        Object.keys(CACHE_GROUP).forEach(key => {
            newIndex.groups[CACHE_GROUP[key]] = [];
        });
        
        // 保存新索引
        saveCacheIndex(newIndex);
    } catch (e) {
        console.error('清空缓存索引失败:', e);
    }
}

/**
 * 启动缓存监控器
 */
function startMonitor() {
    // 如果已经启动，不再重复启动
    if (monitorTimer) return;
    
    // 创建监控器
    monitorTimer = setInterval(() => {
        try {
            // 清理过期缓存
            cleanExpiredCache();
            
            // 检查缓存容量
            const stats = getStats();
            if (!stats) return;
            
            // 如果总容量超过85%，执行清理
            if (stats.total.size > stats.total.limit * 0.85) {
                // 从所有分组清理低优先级缓存
                Object.keys(CACHE_GROUP).forEach(key => {
                    const group = CACHE_GROUP[key];
                    cleanCacheByPriority(group);
                });
            }
            
            // 检查各分组容量
            Object.keys(stats.groups).forEach(group => {
                const groupStat = stats.groups[group];
                // 如果分组容量超过90%，执行清理
                if (groupStat.limit > 0 && groupStat.size > groupStat.limit * 0.9) {
                    cleanCacheByPriority(group);
                }
            });
        } catch (e) {
            console.error('缓存监控器执行失败:', e);
        }
    }, MONITOR_INTERVAL);
}

/**
 * 清理过期缓存
 */
function cleanExpiredCache() {
    try {
        const cacheIndex = getCacheIndex();
        const now = util.time();
        const expiredKeys = [];
        
        // 获取所有缓存项
        for (const key of cacheIndex.keys.map(item => item.key)) {
            try {
                const cacheData = wx.getStorageSync(key);
                if (cacheData && cacheData.expireTime < now) {
                    expiredKeys.push(key);
                }
            } catch (e) {
                // 读取出错，认为缓存无效
                expiredKeys.push(key);
            }
        }
        
        // 批量删除过期项
        expiredKeys.forEach(key => {
            try {
                wx.removeStorageSync(key);
                removeFromCacheIndex(key);
            } catch (e) {
                console.error(`删除过期缓存 ${key} 失败:`, e);
            }
        });
        
    } catch (e) {
        console.error('清理过期缓存失败:', e);
    }
}

// 在应用启动时自动开始监控
startMonitor();

module.exports = {
    CACHE_TIME,
    CACHE_GROUP,
    CACHE_PRIORITY,
    set,
    get,
    remove,
    clear,
    has,
    clearGroup,
    getStats
}; 